from .models import User
import re
from django_redis import get_redis_connection

from rest_framework import serializers
from rest_framework_jwt.settings import api_settings


class CreateUserSerializer(serializers.ModelSerializer):
    """
    注册序列化器
    前端传来的字段：username，password，password2，phone，sms_code，allow

    模型中的字段：id，username，password，phone

    需要序列化的字段：id，username，password，password2，phone，sms_code，allow
    其中：
        需要校验的字段：
        username，password和password2，phone，sms_code，allow

        需要序列化的字段（read_only）：
        id，username，phone

        需要反序列化的字段（write_only）：
        username，password，password2，phone，sms_code，allow

        所有，双向的有 id，username，phone
    """
    # 增加额外字段
    password2 = serializers.CharField(label='确认密码', write_only=True)
    sms_code = serializers.CharField(label='验证码', write_only=True)
    allow = serializers.CharField(label='同意协议', write_only=True)
    token = serializers.CharField(label='token', read_only=True)

    class Meta:
        model = User
        # fields = '__all__'
        fields = ['id', 'username', 'password', 'password2', 'phone', 'sms_code', 'allow', 'token']

        # 调整字段选项参数
        extra_kwargs = {
            'username': {  # 双向的
                'min_length': 5,
                'max_length': 20,
                'error_messages': {  # 序列化出错，自定义报错信息
                    'min_length': '仅允许5-20个字符的⽤户名',
                    'max_length': '仅允许5-20个字符的⽤户名',
                }
            },
            'password': {
                'write_only': True,  # 只做反序列化
                'min_length': 8,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许8-20个字符的密码',
                    'max_length': '仅允许8-20个字符的密码',
                }
            }
        }

    # 反序列化校验
    # # 针对单一字段，追加校验逻辑
    # # # 校验手机号码
    def validate_phone(self, value):
        if not re.match(r'1[3-9]\d{9}$', value):
            raise serializers.ValidationError('手机号码输入错误')
        # 校验什么，就要原封不动的返回什么
        return value

    # # # 校验同意协议
    def validate_allow(self, value):
        if value.lower() != 'true':
            raise serializers.ValidationError('请判断同意协议')
        # 校验什么，就要原封不动的返回什么
        return value

    # 反序列化
    # 联合校验，追加校验逻辑
    def validate(self, attrs):
        """
        :param attrs: 是一个字典
        :return: 校验什么，就要原封不动的返回什么
        """
        # # 校验密码
        if attrs['password'] != attrs['password2']:
            raise serializers.ValidationError('两次密码不一致')

        # # 校验验证码
        # # # 调用全局配置中'smscode'的redis模版
        redis_conn = get_redis_connection('smscode')
        phone = attrs['phone']
        real_sms_code = redis_conn.get("sms_{}".format(phone))
        # 如果验证码失效 或者 验证码不匹配
        # 注意：
        # 1 向redis存储数据时都是以 字符串 类型存储，取出来都是 Bytes 类型
        # 2 这里的逻辑顺序一定要对，先判断real_sms_code是否为None，然后再判断real_sms_code和前端传来的是否一致
        if real_sms_code is None or attrs['sms_code'] != real_sms_code.decode():
            raise serializers.ValidationError('验证码错误')

        return attrs

    # 重写create方法，优化模型数据
    def create(self, validated_data):
        # 把不需要存储的字段删除
        del validated_data['password2']
        del validated_data['sms_code']
        del validated_data['allow']

        # 把明文密码拿出来
        password = validated_data.pop('password')

        # 创建用户模型对象，给模型中的username和phone赋值
        user = User(**validated_data)
        user.set_password(password)  # 把加密后的密码再赋值给模型
        user.save()  # 存储到数据库

        # JWT 生成 token
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER  # 引用jwt中叫JWT_PAYLOAD_HANDLER的函数(生成playload部分)
        """
        源码中： 所有playload中是把id，username和exp（超时时间）做了base64
        payload = {
            'user_id': user.pk,
            'username': username,
            'exp': datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA
        }
        """
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER  # 引用jwt中叫JWT_ENCODE_HANDLER的函数(生成jwt)
        """
        源码：
        def jwt_encode_handler(payload):
            key = api_settings.JWT_PRIVATE_KEY or jwt_get_secret_key(payload)
            return jwt.encode(
                payload,
                key,
                api_settings.JWT_ALGORITHM
            ).decode('utf-8')
        所以，key就是保存在jdango中的KEY
        """
        payload = jwt_payload_handler(user)  # 根据用户生成用户相关的playload
        token = jwt_encode_handler(payload)  # 生成jwt token

        # 序列化器中添加token字段
        user.token = token

        # 响应 注册数据
        return user


class UserDetailSerializer(serializers.ModelSerializer):
    """⽤户详细信息序列化器"""
    class Meta:
        model = User
        fields = ('id', 'username', 'phone', 'email', 'email_active')

class EmailSerializer(serializers.ModelSerializer):
    """
    邮箱序列化器
    """
    class Meta:
        model = User
        fields = ('id', 'email')

        extra_kwargs = {
            'email': {
                'required': True
            }
        }
    # 接收put请求
    def update(self, instance, validated_data):
        instance.email = validated_data['email']
        instance.save()
        return instance

